Skip to content

db: opt-in ReadAhead of Table with limited "ahead window"#21880

Merged
AskAlexSharov merged 75 commits into
mainfrom
alex/warmup_table_36
Jul 8, 2026
Merged

db: opt-in ReadAhead of Table with limited "ahead window"#21880
AskAlexSharov merged 75 commits into
mainfrom
alex/warmup_table_36

Conversation

@AskAlexSharov

@AskAlexSharov AskAlexSharov commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Completely changed PR.

Now:

  • table split on ch"keys amount aware" and equal chunks - by mdbx_cursor_distribute()
  • read-aheader doesn't run too far ahead from consumer (1gb ahead)
  • ClearTable() method now based on mdbxgo_cursor_delete_range() + ReadAheader()

It greatly speedup "clear table" and "prune" operations on chaindata >> RAM case

Speedup tools:

  • integration stage_exec --reset
  • integration mdbx_to_mdbx

ReadAhead is behind WARMUP_TABLE_WORKERS=256 feature-flag.
By default not enabled. But maybe i will auto-enable it - because it's used on offline-maintainance-tools only.

FYI: mdbx_cursor_distribute() is fast on db >> ram because i run it only on BranchNodes of btree: table.stats.depth - 2

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in mechanism to warm specific MDBX tables into the OS page cache to improve operation when chaindata is much larger than RAM, and wires this warmup into several read-heavy workflows (collate/prune, backup/copy, integration stages).

Changes:

  • Extend kv.RoDB / kv.TemporalRoDB with WarmupTable / Warmup APIs and provide implementations (MDBX + no-ops for remote/memory DBs).
  • Integrate per-table warmup into state domain/inverted-index collate/prune and into backup table clear/copy paths.
  • Update call sites/signatures in stagedsync resets and integration commands to pass the DB handle where needed; adjust stage_exec flow around BuildFiles.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
polygon/db/database.go Exposes WarmupTable on Polygon DB wrapper by delegating to underlying kv.RoDB.
execution/stagedsync/stage_custom_trace.go Updates backup.ClearTables call to pass the DB handle.
execution/stagedsync/rawdbreset/reset_stages.go Adds DB arg to reset helpers and passes it to backup.ClearTables for warmup-while-clear.
db/state/inverted_index.go Adds kv.RoDB field and fires background WarmupTable before reading keys table in collate.
db/state/domain.go Fires background WarmupTable before reading domain values table in collate/prune.
db/state/aggregator.go Wires Aggregator DB handle into registered Domains/InvertedIndexes (enables warmup).
db/rawdb/blockio/block_writer.go Passes db into backup.ClearTables when truncating bodies-related tables.
db/kv/temporal/kv_temporal.go Adds TemporalRoDB.Warmup(ctx, force) implementation via underlying MDBX tx warmup.
db/kv/remotedb/kv_remote.go Implements no-op Warmup/WarmupTable for remote DB provider.
db/kv/membatchwithdb/memory_store.go Implements no-op WarmupTable for in-memory store DB.
db/kv/membatchwithdb/memory_mutation.go Implements no-op Warmup/WarmupTable for temporal in-memory DB wrapper.
db/kv/mdbx/kv_mdbx.go Implements MDBX WarmupTable via parallel prefix/seek scans.
db/kv/kv_interface.go Extends interfaces with WarmupTable and Warmup API contracts.
db/kv/helpers.go Forwards WarmupTable through gatedRoDB.
db/kv/backup/backup.go Adds warmupWhile helper; warms tables during Kv2kv and ClearTables; updates signatures.
common/dbg/experiments.go Adds env-controlled WARMUP_TABLE_WORKERS knob (default 0 disables warmup).
cmd/integration/commands/stages.go Updates reset call signature; modifies stageExec commit/build flow.
cmd/integration/commands/reset_state.go Updates backup.ClearTables call to pass DB handle.
cmd/integration/commands/refetence_db.go Updates backup.Kv2kv call signature (drops threads arg).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread cmd/integration/commands/stages.go Outdated
@AskAlexSharov AskAlexSharov changed the title db/kv, db/state, execution: opt-in per-table page-cache warmup [wip] db: opt-in per-table warmup Jun 18, 2026
@AskAlexSharov AskAlexSharov requested a review from Copilot June 18, 2026 09:20
@yperbasis yperbasis added this to the 3.6.0 milestone Jun 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/backup/backup.go Outdated
Comment thread db/kv/helpers.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Comment thread db/kv/mdbx/kv_mdbx.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go Outdated
@yperbasis

Copy link
Copy Markdown
Member

A few substantive concerns on the warmup logic before this comes out of WIP:

1. No parallelism on counter-keyed tables. WarmupTable partitions by the first 2 bytes (Prefix([]byte{i,j})), which only fans out when those bytes are well-distributed (domain ValuesTable — the big win). For 8-byte-BE counter keys (txNum/blockNum) the top 2–4 bytes are always 0x00 even at mainnet scale, so the whole table sits under prefix [0,0] and one goroutine scans it while the other 65 535 find nothing. This hits ii.KeysTable — exactly what the II collate warmup targets — plus EthTx/MaxTxNum/Senders (Kv2kv/TruncateBodies/ResetSenders). Those paths degenerate to a single-threaded full scan.

2. The 1000-goroutine second loop is redundant. Prefix(8-byte seek) = Range(seek, NextSubtree(seek)) matches only keys whose first 8 bytes equal seek — it doesn't scan between seeks. So its coverage is a strict subset of loop 1 (every seek starts with 00 00), it double-counts into progress, and it doesn't actually help the counter tables it looks aimed at. Either drop it, or replace both loops with Range(seek_i, seek_{i+1}) partitioning — which would also fix point 1.

3. Long-lived read txns. Each prefix scan wraps the full iteration in one db.View (one read txn). The dominant [0,0] goroutine on a counter table then holds a single reader open for the entire >>RAM scan, concurrent with the collate/prune writes that spawned it → pins the MVCC snapshot and blocks free-page reclamation (DB bloat). Same in ClearTables (warm-while-drop pins the pages the drop frees). Worth bounding scan-txn lifetime before this is enabled anywhere.

4. The stage_exec change is always-on, not gated by the flag. The new commit → BuildFiles(EndTxNumMinimax()+StepSize()) → reopen block is gated by !noCommit, not WARMUP_TABLE_WORKERS, so it changes integration stage_exec regardless of the feature (synchronous build + extra commit/reopen per iteration). Probably worth splitting out / calling out. Also EndTxNumMinimax()+StepSize() builds only one step past the frontier per iteration with no final catch-up — intended?

Minor: the new // TODO in backupTable (sequence/Unwind) has no linked issue/owner and is unrelated to warmup — per repo policy, file an issue or drop it.

@AskAlexSharov AskAlexSharov force-pushed the alex/warmup_table_36 branch from d3aa6e4 to 6bf1e15 Compare June 19, 2026 01:50
@AskAlexSharov AskAlexSharov requested a review from Copilot June 19, 2026 01:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AskAlexSharov AskAlexSharov requested a review from Copilot June 19, 2026 01:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AskAlexSharov AskAlexSharov force-pushed the alex/warmup_table_36 branch 3 times, most recently from b83f030 to 6aea736 Compare June 21, 2026 06:45
@AskAlexSharov AskAlexSharov changed the title [wip] db: opt-in per-table warmup [wip] db: opt-in ReadAhead with "run too far ahead" prevention Jun 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Comment thread db/kv/temporal/kv_temporal.go
Comment thread db/kv/readahead.go
- ReadAhead.run: defer cancel() so the child context and its ctx-cancel watcher
  goroutine are released even if a caller forgets Close() (the nil-safe API
  invites fire-and-forget).
- DistributeCursors doc: interior boundaries are tx-owned and invalidated by any
  same-tx write — clone before mutating (matches how DistributeBounds uses them).
- ClearTables doc: trim scope/fallback narration, keep the atomicity/deadlock why.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AskAlexSharov

Copy link
Copy Markdown
Collaborator Author

@yperbasis cr plz

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Comment thread execution/stagedsync/rawdbreset/reset_stages.go Outdated
Comment thread db/kv/mdbx/kv_mdbx.go

@yperbasis yperbasis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at head 6e52947. No correctness bugs found. Findings by severity:

Should fix

  • db/kv/readahead.go:126 — the ~1GB ahead-window guarantee breaks on dup-heavy DupSort tables: interior bounds are key-granular and equal keys are deduped, so a table with few distinct keys collapses to ~1 chunk regardless of size (repro: 1-distinct-key 124MB DupSort table → a single chunk holding all 2.2M entries). One hot key with a >1GB dup subtree (e.g. the Transfer topic in LogTopicsIdx with a large unfrozen tail) makes warm() fault the entire table at once. Key-granular bounds can't split a dup run, so the fix is clamping bytes faulted inside warm() (stop ~1GB ahead of SetPos).

Medium (efficiency of the new path)

  • db/kv/backup/backup.go:220len(bounds) < 2 never fires for non-nil bounds (DistributeCursors always returns ≥ 2 entries; for sizes in [32MB, 64MB) n==1 returns exactly [nil, nil]), so the one-chunk case takes full-table read-ahead + whole-table DeleteRange instead of the native drop the comment intends. Should be <= 2.
  • db/kv/readahead.go:234warm() via tx.Range costs ~3 cgo mdbx_cursor_get per key (redundant Current in both HasNext and Next, plus the advance). A raw cursor Seek/Next loop bounded by bytes.Compare(k, to) — the same pattern as backupTable's copy loop — is 1 cgo call per key on a pass that exists only to fault pages.
  • db/kv/mdbx/delete_range_test.go — the chunked DeleteRange path has no DupSort coverage, yet ResetExec/StageCustomTraceReset clear >32MB DupSort tables through it when the flag is on. It behaves correctly today (verified out-of-repo: 30k×8 and 50×20k key/dup shapes, exact counts, Count==0), but nothing in-repo pins it — please add a DupSort chunked-clear case.

Low (design/hygiene)

  • db/kv/readahead.go:91 — over-synchronized: consumerChunk's only pure read is already under mu (a plain int64 mutated under mu suffices); bounds/logLvl are set-once and could be plain fields assigned before go r.run(...) (which also removes the SetPos startup nil-window); the warming/idle gauges + dedicated logger goroutine feed one 20s line both callers already log themselves.
  • db/kv/backup/backup.go:194 — the new db kv.RoDB param (inert unless WARMUP_TABLE_WORKERS>0) could instead be recovered from the tx via an optional interface{ DB() kv.RoDB } on MdbxTx + temporal forwarder — the same pattern as HasDeleteRange in this PR — undoing the call-site ripples and the ResetSenders reshape.
  • db/kv/temporal/kv_temporal.go:396 — temporal RwTx satisfies HasDeleteRange unconditionally, so clearTable's !ok → ClearTable degrade is dead code for temporal txs, and a future non-mdbx inner would hard-error mid-clear while the sibling DistributeCursors forwarder silently degrades. Forward the capability conditionally, or unify the two fallback policies.
  • db/kv/helpers.go:182Deprecated: use NewReadAhead. is misleading: NewReadAhead has no bounded-amount mode, so the two DumpTxs callers can't migrate mechanically. Either migrate them or drop the marker.

Nits

  • db/kv/backup/backup.go:248 — a BucketSize failure inside the 20s progress tick aborts the whole clear; log-and-continue (the trigger is near-unreachable, but coupling operation success to a progress line is wrong).
  • db/kv/mdbx/delete_range_test.go:34u64Key duplicates u64tob already in this package.

- readahead: cap warm() at ~1GB/chunk so a dup-heavy DupSort chunk (one key with a
  multi-GB dup run, which branch-level DistributeCursors can't split) doesn't fault
  the whole table at once; rewrite warm() as a raw-cursor Seek/Next loop (1 cgo
  Get/key vs Range's ~3); drop the redundant internal progress logger + gauges
  (callers already log); make bounds a set-once field and consumerChunk a plain
  int64 under mu (removes the atomics and the SetPos startup nil-window).
- backup.clearTable: one-chunk case (bounds==[nil,nil], len 2) now takes the native
  drop (was len<2, never true) instead of full-table warm + whole-table DeleteRange;
  a BucketSize failure in the progress tick no longer aborts the clear.
- temporal: DistributeCursors forwarder fails loud on a non-mdbx inner, matching
  DeleteRange (was silent degrade — inconsistent).
- reset_stages: wrap ClearTables errors with stage context.
- helpers: drop the misleading `// Deprecated:` marker (NewReadAhead has no
  amount-bounded mode the DumpTxs callers could migrate to).
- tests: DupSort DeleteRange + chunked-clear coverage; DupSort skew test proving
  DistributeCursors splits at main-key granularity (hot key not split across chunks).
@AskAlexSharov

AskAlexSharov commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

@yperbasis thanks — addressed the head-6e529478d round in 8297a0c:

Medium

  • len(bounds) < 2<= 2: the one-chunk case ([nil,nil]) now takes the native drop instead of full-table warm + whole-table DeleteRange.
  • warm() rewritten as a raw-cursor Seek/Next loop (1 cgo Get/key vs Range's ~3).
  • DupSort chunked-clear now covered (TestChunkedDeleteRangeDupSortCoversAllKeys + TestMdbxDeleteRangeDupSort).

Low

  • readahead over-synchronization: dropped the internal logger goroutine + warming/idle gauges (callers already log); bounds is set-once, consumerChunk a plain int64 under mu (removes the atomics + the SetPos startup nil-window).
  • temporal DistributeCursors forwarder now fails loud on a non-mdbx inner, matching DeleteRange (unified the two fallback policies).
  • helpers.go: dropped the // Deprecated: marker (no amount-bounded mode for the DumpTxs callers to migrate to).

Nits

  • BucketSize failure in the progress tick no longer aborts the clear (log-and-continue).
  • u64Key → the existing u64tob.

Deferred — the db kv.RoDB param → interface{ DB() kv.RoDB }: keeping the explicit param for now — Id rather the read-ahead dependency be visible at the call sites than recovered from a hidden accessor on the tx; the ripple is small. Happy to switch if you feel strongly.

make lint + make erigon integration green; Windows shards green.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AskAlexSharov

Copy link
Copy Markdown
Collaborator Author

About DupSort sub-keys chunks equality:
Unfortunately touching Leaf nodes of Btree will make DistributeCursors very-very slow (Can take hours on chaindata >> RAM case). It means DistributeCursors func will need own multi-workers-warmup machinery (which will suffer from bad chunks equality too). See deepness = st.Depth - 2
But anyway - even in DupSort case this PR is much better than what we had in the past.

So, if you want you can create follow-up issue about "ReadAhead of DupSort tables, when table >> RAM, when 1 key has 1Bil of sub-keys, after sync && sudo sysctl vm.drop_caches=3". Maybe it's possible by moving estimation inside workers:
For example:

  • do high-level DistributeCursors first. Then inside workers - do additional: tx.DistributeCursors or Txn.EstimateRange or Cursor.EstimateMove or Cursor.EstimateDistance.

@AskAlexSharov

Copy link
Copy Markdown
Collaborator Author

How it looks now no 500gb db:

INFO[07-07|03:38:38.880] [clear]                                  table=ChangeSets3 size=312.8GB
INFO[07-07|03:38:59.272] [clear]                                  table=ChangeSets3 speed=1.1GB/s keys=293.93k/s remaining=289.6GB
INFO[07-07|03:39:18.886] [clear]                                  table=ChangeSets3 speed=756.0MB/s keys=190.62k/s remaining=275.2GB
INFO[07-07|03:39:38.938] [clear]                                  table=ChangeSets3 speed=671.0MB/s keys=169.20k/s remaining=262.0GB
INFO[07-07|03:39:58.933] [clear]                                  table=ChangeSets3 speed=668.8MB/s keys=168.64k/s remaining=248.9GB
INFO[07-07|03:40:18.960] [clear]                                  table=ChangeSets3 speed=656.0MB/s keys=165.40k/s remaining=236.1GB
INFO[07-07|03:40:38.894] [clear]                                  table=ChangeSets3 speed=659.0MB/s keys=166.16k/s remaining=223.3GB
INFO[07-07|03:40:58.960] [clear]                                  table=ChangeSets3 speed=670.4MB/s keys=169.02k/s remaining=210.2GB
INFO[07-07|03:41:18.896] [clear]                                  table=ChangeSets3 speed=659.2MB/s keys=166.20k/s remaining=197.3GB
INFO[07-07|03:41:34.260] [mem] memory stats                       Rss=40.9GB Size=0B Pss=40.5GB SharedClean=908.8MB SharedDirty=0B PrivateClean=33.1GB PrivateDirty=6.9GB Referenced=40.9GB Anonymous=6.9GB Swap=0B alloc=3.6GB sys=7.6GB
WARN[07-07|03:41:34.261] [mdbx_to_mdbx] delete                    table=ChangeSets3 took=1.202497729s
INFO[07-07|03:41:39.072] [clear]                                  table=ChangeSets3 speed=608.6MB/s keys=153.45k/s remaining=185.3GB
INFO[07-07|03:41:58.915] [clear]                                  table=ChangeSets3 speed=673.8MB/s keys=169.89k/s remaining=172.3GB
INFO[07-07|03:42:18.928] [clear]                                  table=ChangeSets3 speed=672.0MB/s keys=169.45k/s remaining=159.1GB
INFO[07-07|03:42:38.884] [clear]                                  table=ChangeSets3 speed=670.1MB/s keys=168.97k/s remaining=146.1GB
INFO[07-07|03:42:58.895] [clear]                                  table=ChangeSets3 speed=672.3MB/s keys=169.51k/s remaining=132.9GB
INFO[07-07|03:43:18.964] [clear]                                  table=ChangeSets3 speed=670.4MB/s keys=169.02k/s remaining=119.8GB
INFO[07-07|03:43:38.975] [clear]                                  table=ChangeSets3 speed=672.1MB/s keys=169.47k/s remaining=106.7GB
INFO[07-07|03:43:58.901] [clear]                                  table=ChangeSets3 speed=671.2MB/s keys=169.23k/s remaining=93.6GB
INFO[07-07|03:44:18.938] [clear]                                  table=ChangeSets3 speed=671.5MB/s keys=169.30k/s remaining=80.5GB
WARN[07-07|03:44:34.426] [mdbx_to_mdbx] delete                    table=ChangeSets3 took=1.336049337s
INFO[07-07|03:44:34.426] [mem] memory stats                       Rss=40.5GB Size=0B Pss=40.1GB SharedClean=908.8MB SharedDirty=0B PrivateClean=35.5GB PrivateDirty=4.1GB Referenced=40.5GB Anonymous=4.1GB Swap=0B alloc=3.6GB sys=7.6GB
INFO[07-07|03:44:38.931] [clear]                                  table=ChangeSets3 speed=629.9MB/s keys=158.82k/s remaining=68.2GB
INFO[07-07|03:44:58.949] [clear]                                  table=ChangeSets3 speed=675.9MB/s keys=170.43k/s remaining=55.0GB
INFO[07-07|03:45:18.944] [clear]                                  table=ChangeSets3 speed=672.8MB/s keys=169.63k/s remaining=41.8GB
INFO[07-07|03:45:38.951] [clear]                                  table=ChangeSets3 speed=672.4MB/s keys=169.53k/s remaining=28.7GB
INFO[07-07|03:45:58.968] [clear]                                  table=ChangeSets3 speed=672.0MB/s keys=169.42k/s remaining=15.5GB
INFO[07-07|03:46:18.949] [clear]                                  table=ChangeSets3 speed=673.4MB/s keys=169.78k/s remaining=2.4GB
INFO[07-07|03:46:22.441] [clear]                                  table=AccountHistoryKeys size=116.5MB
INFO[07-07|03:46:23.285] [clear]                                  table=AccountIdx size=0B
INFO[07-07|03:46:23.305] [clear]                                  table=AccountHistoryVals size=164.7MB
INFO[07-07|03:46:24.058] [clear]                                  table=AccountVals size=41.4MB
INFO[07-07|03:46:25.091] [clear]                                  table=StorageHistoryKeys size=30.1GB
INFO[07-07|03:46:45.116] [clear]                                  table=StorageHistoryKeys speed=891.5MB/s keys=9.73M/s remaining=12.7GB
INFO[07-07|03:47:01.111] [clear]                                  table=StorageIdx size=0B
INFO[07-07|03:47:31.272] [clear]                                  table=StorageHistoryVals size=47.3GB
WARN[07-07|03:47:31.794] [mdbx_to_mdbx] delete                    table=StorageHistoryVals took=521.613375ms
INFO[07-07|03:47:34.538] [mem] memory stats                       Rss=40.4GB Size=0B Pss=40.0GB SharedClean=907.4MB SharedDirty=0B PrivateClean=35.3GB PrivateDirty=4.2GB Referenced=40.4GB Anonymous=4.2GB Swap=0B alloc=3.6GB sys=7.6GB
WARN[07-07|03:47:34.557] [mdbx_to_mdbx] delete                    table=StorageHistoryVals took=1.464483526s
INFO[07-07|03:47:51.291] [clear]                                  table=StorageHistoryVals speed=707.7MB/s keys=4.93M/s remaining=33.4GB
INFO[07-07|03:48:11.273] [clear]                                  table=StorageHistoryVals speed=773.1MB/s keys=5.37M/s remaining=18.4GB
INFO[07-07|03:48:31.296] [clear]                                  table=StorageHistoryVals speed=757.1MB/s keys=5.26M/s remaining=3.6GB
INFO[07-07|03:49:10.271] [clear]                                  table=StorageVals size=52.9GB
INFO[07-07|03:49:30.331] [clear]                                  table=StorageVals speed=761.2MB/s keys=4.72M/s remaining=37.9GB
INFO[07-07|03:49:50.295] [clear]                                  table=StorageVals speed=774.4MB/s keys=4.80M/s remaining=22.9GB
INFO[07-07|03:50:10.309] [clear]                                  table=StorageVals speed=756.5MB/s keys=4.69M/s remaining=8.1GB
INFO[07-07|03:50:21.312] [clear]                                  table=CodeHistoryKeys size=5.0MB
INFO[07-07|03:50:21.416] [clear]                                  table=CodeIdx size=0B
INFO[07-07|03:50:21.416] [clear]                                  table=CodeHistoryVals size=7.4MB
INFO[07-07|03:50:21.439] [clear]                                  table=CodeVals size=3.6GB
INFO[07-07|03:50:22.188] [clear]                                  table=CommitmentHistoryKeys size=0B
INFO[07-07|03:50:22.188] [clear]                                  table=CommitmentIdx size=0B
INFO[07-07|03:50:22.188] [clear]                                  table=CommitmentHistoryVals size=0B
INFO[07-07|03:50:34.580] [mem] memory stats                       Rss=40.2GB Size=0B Pss=39.7GB SharedClean=907.4MB SharedDirty=0B PrivateClean=35.0GB PrivateDirty=4.3GB Referenced=40.2GB Anonymous=4.3GB Swap=0B alloc=3.6GB sys=7.6GB
INFO[07-07|03:50:44.137] [clear]                                  table=CommitmentVals size=63.5GB
INFO[07-07|03:51:04.167] [clear]                                  table=CommitmentVals speed=770.3MB/s keys=864.03k/s remaining=48.5GB
INFO[07-07|03:51:24.150] [clear]                                  table=CommitmentVals speed=776.0MB/s keys=1.13M/s remaining=33.3GB
INFO[07-07|03:51:44.161] [clear]                                  table=CommitmentVals speed=762.4MB/s keys=1.89M/s remaining=18.4GB
INFO[07-07|03:52:04.181] [clear]                                  table=CommitmentVals speed=765.5MB/s keys=1.89M/s remaining=3.4GB
INFO[07-07|03:52:08.656] [clear]                                  table=ReceiptHistoryKeys size=22.2MB
INFO[07-07|03:52:09.098] [clear]                                  table=ReceiptIdx size=0B
INFO[07-07|03:52:09.099] [clear]                                  table=ReceiptHistoryVals size=21.6MB
INFO[07-07|03:52:09.102] [clear]                                  table=ReceiptVals size=4.0KB
INFO[07-07|03:52:09.102] [clear]                                  table=ReceiptCacheHistoryKeys size=0B
INFO[07-07|03:52:09.102] [clear]                                  table=ReceiptCacheIdx size=0B
INFO[07-07|03:52:09.102] [clear]                                  table=ReceiptCacheHistoryVals size=0B
INFO[07-07|03:52:09.102] [clear]                                  table=ReceiptCacheVals size=0B
INFO[07-07|03:52:09.102] [clear]                                  table=LogAddressKeys size=9.5MB
INFO[07-07|03:52:09.276] [clear]                                  table=LogAddressIdx size=15.3MB
INFO[07-07|03:52:09.357] [clear]                                  table=LogTopicsKeys size=36.7MB
INFO[07-07|03:52:09.942] [clear]                                  table=LogTopicsIdx size=63.7MB
INFO[07-07|03:52:10.727] [clear]                                  table=TracesFromKeys size=52.0MB
INFO[07-07|03:52:11.755] [clear]                                  table=TracesFromIdx size=53.8MB
INFO[07-07|03:52:12.145] [clear]                                  table=TracesToKeys size=58.9MB
INFO[07-07|03:52:13.310] [clear]                                  table=TracesToIdx size=67.6MB
INFO[07-07|03:52:16.551] total                                    took=13m40.769985298s

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Comment thread db/kv/mdbx/kv_mdbx.go
Comment thread db/kv/backup/backup.go
AskAlexSharov and others added 5 commits July 8, 2026 07:53
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
A Copilot autofix dropped the `if !allSet { break }` guard in the
cursor-position loop, turning the expected end-of-prefix Current error on
unset surplus cursors into a hard failure. This broke
TestSplitBucketByCountFewerPositions (fewer positions than n).
Bump mdbx-go to v0.40.3, which maps MDBX_ENODATA (GET_CURRENT on a
never-positioned cursor) to the new ErrNoData sentinel. Current() now
treats it as end-of-data (k==nil), like NOTFOUND.

DistributeCursors leaves surplus cursors hollow when the range has fewer
positions than n; Current() on them used to leak ENODATA as a hard error,
worked around by a blanket `if !allSet { break }` that also swallowed real
faults. With ErrNoData normalized, drop that band-aid: the existing
k==nil check ends the prefix and genuine errors propagate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants